/*
 *	Copyright (c) 2009, libBasement
 *	All rights reserved.
 *	
 *	Redistribution and use in source and binary forms, with or without modification,
 *	are permitted provided that the following conditions are met:
 *	
 *	Redistributions of source code must retain the above copyright notice,
 *	this list of conditions and the following disclaimer.
 *	Redistributions in binary form must reproduce the above copyright notice,
 *	this list of conditions and the following disclaimer in the documentation
 *	and/or other materials provided with the distribution.
 *	Neither the name of the <ORGANIZATION> nor the names of its contributors may
 *	be used to endorse or promote products derived from this software without
 *	specific prior written permission.
 *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "BObject.h"
#include "BAutoreleasePool.h"
#include "BString.h"
#include "BException.h"
#include "BAllocator.h"
#include "BNumber.h"
#include <cstdlib>
#include <cstdio>

namespace Basement
{
	Object *$(Object *object)
	{
		return object;
	}
	
	Object *$s(Object *object)
	{
		return object;
	}
	
#pragma mark Creation & Destruction
	
	void *Object::operator new(size_t size, Allocator allocator)
	{
		Object *self = (Object *)allocator.allocate(size);
		if(!self)
		{
			puts("Could not allocate space for new Object.");
			throw "Could not allocate space for new Object.";
		}
		
		self->_retainCount = 0;
		self->_isConstant = false;
		self->_allocator = allocator;
		
		return self;
	}
	
	void Object::operator delete(void *self)
	{
		((Object *)self)->_allocator.deallocate(self);
	}
	
	Object::~Object()
	{
		this->dealloc();
	}
	
#pragma mark -
#pragma mark Initialization
	
	Object *Object::init()
	{
		_retainCount++;
		return this;
	}
	
	String *Object::description()
	{
		//strlen("Basement::") + strlen(classname) + strlen("#") + strlen("<", ">"), + 0x12345678 
		char buffer[8 + strlen(this->className()) + 1 + 2 + 10];
		sprintf(buffer, "<Basement::%s#%p>", this->className(), this);
		
		std::string string(buffer);
		return String::withStdString(string);
	}
	
#pragma mark -
#pragma mark Memory management
	
	void Object::dealloc()
	{
		//Do nothing..
	}
	
	Object *Object::retain()
	{
		_retainCount++;
		return this;
	}
	
	void Object::release()
	{
		_retainCount--;
		if(_retainCount <= 0)
		{
			if(_isConstant)
			{
				delete this;
			}
		}
	}
	
	Object *Object::autorelease()
	{
		AutoreleasePoolAddObject(this, AutoreleasePoolGetCurrent());
		return this;
	}
	
	Integer Object::retainCount()
	{
		return _retainCount;
	}
	
#pragma mark -
#pragma mark Equality
	
	UInteger Object::hash()
	{
		return (UInteger)this;
	}
	
	bool Object::isEqual(Object *other)
	{
		return (this->hash() == other->hash());
	}
	
#pragma mark -
#pragma mark Theoretical KVC
	
	void Object::willChangeValueForKey(String *key)
	{
		
	}
	
	void Object::didChangeValueForKey(String *key)
	{
		
	}
	
#pragma mark -
	
	void Object::setValueForKey(Object *value, String *key)
	{
		this->willChangeValueForKey(key);
		
		//No-op
		
		this->didChangeValueForKey(key);
	}
	
	Object *Object::valueForKey(Object *value, String *key)
	{
		//No-op
		return NULL;
	}
}
